package com.wmada.spring.error;

import com.wmada.spring.api.ApiResult;
import org.springframework.context.MessageSource;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ValidationException;
import java.util.Locale;

/**
 * @author will.ma
 * @date 2020-9-27
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    private final MessageSource messageSource;

    public GlobalExceptionHandler() {
        ReloadableResourceBundleMessageSource reloadableResourceBundleMessageSource = new ReloadableResourceBundleMessageSource();
        reloadableResourceBundleMessageSource.setBasename("classpath:ValidationMessages");
        reloadableResourceBundleMessageSource.setDefaultEncoding("UTF-8");
        messageSource = reloadableResourceBundleMessageSource;
    }

    @ExceptionHandler(value = ApiException.class)
    public ApiResult<Void> handle(ApiException e) {
        if (e.getErrorCode() != null) {
            return ApiResult.failure(e.getErrorCode());
        }
        return ApiResult.failure(e.getMessage());
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public ApiResult<Void> handleValidException(MethodArgumentNotValidException e, Locale locale) {
        return handleBindingResult(e.getBindingResult(), locale);
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = ValidationException.class)
    public ApiResult<Void> handleValidException(ValidationException e) {
        return ApiResult.validateFailed(e.getMessage());
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = BindException.class)
    public ApiResult<Void> handleValidException(BindException e, Locale locale) {
        return handleBindingResult(e.getBindingResult(), locale);
    }

    private ApiResult<Void> handleBindingResult(BindingResult bindingResult, Locale locale) {
        String message = null;
        if (bindingResult.hasErrors()) {
            FieldError fieldError = bindingResult.getFieldError();
            if (fieldError != null) {
                message = messageSource.getMessage("validation.object", null, locale) + " [" + fieldError.getObjectName() + "] ";
                message += messageSource.getMessage("validation.middle", null, locale) + messageSource.getMessage("validation.field", null, locale);
                message += " [" + fieldError.getField() + "]: " + fieldError.getDefaultMessage();
            }
        }
        return ApiResult.validateFailed(message);
    }
}
